using System;

namespace DeflateLib
{
    /// <summary>
    /// Compressor settings data class. 
    /// 
    /// Settings were borrowed from the ZLIB project. Levels of 
    /// compression has same values, but were tuned to current 
    /// implementation. Used in this project for research purpose
    /// and may not work as in the ZLIB.
    /// </summary>
    class LZ77CompressorSettings
    {
        public static readonly LZ77CompressorSettings MaxSearch;
        public static readonly LZ77CompressorSettings NoSearch;
        public static readonly LZ77CompressorSettings Default;

        int goodLength = 0;
        int maxLazy = 0;
        int niceLength = 0;
        int maxChainLength = 0;

        /// <summary>
        /// Tells compressor to reduce search if that length is found.
        /// </summary>
        public int GoodLength
        {
            get { return goodLength; }
            set { goodLength = value; }
        }

        /// <summary>
        /// Tells compressor to ignore lazy search if that length is found.
        /// </summary>
        public int MaxLazy
        {
            get { return maxLazy; }
            set { maxLazy = value; }
        }

        /// <summary>
        /// Tells compressor to stop search if that length is found.
        /// </summary>
        public int NiceLength
        {
            get { return niceLength; }
            set { niceLength = value; }
        }

        /// <summary>
        /// Max amount of steps associated with specific hash.
        /// </summary>
        public int MaxChainLength
        {
            get { return maxChainLength; }
            set { maxChainLength = value; }
        }

        static LZ77CompressorSettings()
        {
            LZ77CompressorSettings maxSearchSettings = new LZ77CompressorSettings();
            maxSearchSettings.goodLength = DeflateUtils.MaxDistance;
            maxSearchSettings.maxLazy = DeflateUtils.MaxDistance;
            maxSearchSettings.niceLength = DeflateUtils.MaxDistance;
            maxSearchSettings.maxChainLength = DeflateUtils.MaxDistance;
            LZ77CompressorSettings.MaxSearch = maxSearchSettings;

            LZ77CompressorSettings noSearchSettings = new LZ77CompressorSettings();
            noSearchSettings.GoodLength = 0;
            noSearchSettings.MaxLazy = 0;
            noSearchSettings.NiceLength = 0;
            noSearchSettings.MaxChainLength = 0;
            LZ77CompressorSettings.NoSearch = noSearchSettings;

            LZ77CompressorSettings.Default = CreateUsingLevel(1);
        }

        /// <summary>
        /// Creates predefined compressor settings. Same as in the ZLIB.
        /// </summary>
        /// <param name="level">Level in range 0-9 (0 - no compression, 9 - max compression).</param>
        /// <returns>Predefined compressor settings.</returns>
        public static LZ77CompressorSettings CreateUsingLevel(int level)
        {
            LZ77CompressorSettings settings = new LZ77CompressorSettings();
            switch (level)
            {
                case 0:
                    settings.GoodLength = 0;
                    settings.MaxLazy = 0;
                    settings.NiceLength = 0;
                    settings.MaxChainLength = 0;
                    break; /* store only */
                case 1:
                    settings.GoodLength = 4;
                    settings.MaxLazy = 4;
                    settings.NiceLength = 8;
                    settings.MaxChainLength = 4;
                    break; /* max speed, no lazy matches */
                case 2:
                    settings.GoodLength = 4;
                    settings.MaxLazy = 5;
                    settings.NiceLength = 16;
                    settings.MaxChainLength = 8;
                    break;
                case 3:
                    settings.GoodLength = 4;
                    settings.MaxLazy = 6;
                    settings.NiceLength = 32;
                    settings.MaxChainLength = 32;
                    break;
                case 4:
                    settings.GoodLength = 4;
                    settings.MaxLazy = 4;
                    settings.NiceLength = 16;
                    settings.MaxChainLength = 16;
                    break; /* lazy matches */
                case 5:
                    settings.GoodLength = 8;
                    settings.MaxLazy = 16;
                    settings.NiceLength = 32;
                    settings.MaxChainLength = 32;
                    break;
                case 6:
                    settings.GoodLength = 8;
                    settings.MaxLazy = 16;
                    settings.NiceLength = 128;
                    settings.MaxChainLength = 128;
                    break;
                case 7:
                    settings.GoodLength = 8;
                    settings.MaxLazy = 32;
                    settings.NiceLength = 128;
                    settings.MaxChainLength = 256;
                    break;
                case 8:
                    settings.GoodLength = 32;
                    settings.MaxLazy = 128;
                    settings.NiceLength = 258;
                    settings.MaxChainLength = 1024;
                    break;
                case 9:
                    settings.GoodLength = 32;
                    settings.MaxLazy = 258;
                    settings.NiceLength = 258;
                    settings.MaxChainLength = 4096;
                    break; /* max compression */
                default:
                    throw new ArgumentOutOfRangeException("level");
            }
            return settings;
        }
    }
}
